﻿using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;

namespace PathFinding
{

    public class Grid
    {
        // col = x  row = y 
        private Cell[,] grid;
        public int col;
        public int row;
        public int cellSize;
        public int startX;
        public int startY;
        public Grid(int startX, int startY, int col, int row, int cellSize, int[] unwalkX, int[] unwalkY)
        {
            this.col = col;
            this.row = row;
            this.cellSize = cellSize;
            this.startX = startX;
            this.startY = startY;
            grid = new Cell[col, row];
            for (int x = 0; x < col; x++)
            {
                for (int y = 0; y < row; y++)
                {
                    Cell cell = new Cell();
                    cell.x = x;
                    cell.y = y;
                    cell.isWalkable = true;
                    grid[x, y] = cell;
                }
            }
            for (int i = 0; i < unwalkX.Length; i++)
            {
                int x = unwalkX[i];
                int y = unwalkY[i];
                this[x, y].isWalkable = false;
            }
        }
        public Grid()
        {

        }

        //异步初始化
        public IEnumerator initAsync(int startX, int startY, int col, int row, int cellSize, int[] unwalkX, int[] unwalkY)
        {
            this.col = col;
            this.row = row;
            this.cellSize = cellSize;
            this.startX = startX;
            this.startY = startY;
            grid = new Cell[col, row];

            for (int x = 0; x < col; x++)
            {
                for (int y = 0; y < row; y++)
                {
                    Cell cell = new Cell();
                    cell.x = x;
                    cell.y = y;
                    cell.isWalkable = true;
                    grid[x, y] = cell;                    
                }
                yield return new WaitForEndOfFrame();
            }
            for (int i = 0; i < unwalkX.Length; i++)
            {
                int x = unwalkX[i];
                int y = unwalkY[i];
                this[x, y].isWalkable = false;
            }
            Debug.LogError("initAsync finish");
        }

        public Cell this[int x, int y]
        {
            get
            {
                return grid[x, y];
            }
        }

        public bool isInBound(int x, int y)
        {
            return x < this.col && y < this.row && x >= 0 && y >= 0;
        }

        public int getCol(float x)
        {
            float sub = x - startX;
            int val = CeilToInt(sub / cellSize);
            return val - 1;
        }
        public int getRow(float y)
        {
            float sub = y - startY;
            int val = CeilToInt(sub / cellSize);
            return val - 1;
        }

        // Returns the smallest integer greater to or equal to /f/.
        int CeilToInt(float f) { return (int)Math.Ceiling(f); }

        // Returns the largest integer smaller to or equal to /f/.
        int FloorToInt(float f) { return (int)Math.Floor(f); }

        public Vector3 getPosByIndex(int x, int y)
        {
            Vector3 pos = Vector3.zero;
            float size = this.cellSize;
            pos.y = 0;
            pos.x = startX + x * size + size / 2;
            pos.z = startY + y * size + size / 2;
            return pos;
        }

        public Cell getCellByPos(Vector3 pos)
        {
            float size = this.cellSize;
            int x = Mathf.CeilToInt((pos.x - startX) / size) - 1;
            int y = Mathf.CeilToInt((pos.z - startY) / size) - 1;
            if (isInBound(x, y))
            {
                return this[x, y];
            }
            return null;
        }

#if UNITY_EDITOR        
        public void draw()
        {
            if (this.grid != null)
            {
                for (int x = 0; x < col; x++)
                {
                    for (int y = 0; y < row; y++)
                    {
                        Cell cell = this[x, y];
                        if (cell != null)
                        {
                            Gizmos.color = cell.isWalkable ? Color.white : Color.red;
                            Vector3 pos = getPosByIndex(x, y);
                            drawBox(pos);
                        }
                    }
                }
            }
        }

        public static void drawBox(Vector3 pos, float cellSize = 1f)
        {
            float y = pos.y;// 1f;
            float scale = 0.95f;
            float halfSize = cellSize * 0.5f * scale;
            Vector3 p1 = new Vector3(pos.x + halfSize, y, pos.z - halfSize);
            Vector3 p2 = new Vector3(pos.x + halfSize, y, pos.z + halfSize);
            Vector3 p3 = new Vector3(pos.x - halfSize, y, pos.z + halfSize);
            Vector3 p4 = new Vector3(pos.x - halfSize, y, pos.z - halfSize);
            Gizmos.DrawLine(p1, p2);
            Gizmos.DrawLine(p2, p3);
            Gizmos.DrawLine(p3, p4);
            Gizmos.DrawLine(p4, p1);
        }

        public static void drawLine(Vector3 p1, Vector3 p2)
        {
            Gizmos.DrawLine(p1, p2);
        }
#endif

    }

}
